import { Request, Response } from 'express';
import { WeightDao } from '../dao/WeightDao';
import { ApiResponse, WeightRecord, KLineQuery } from '../types';
import Joi from 'joi';
import moment from 'moment';

export class WeightController {
  private weightDao: WeightDao;

  constructor() {
    this.weightDao = new WeightDao();
  }

  // 添加体重记录
  addWeight = async (req: Request, res: Response) => {
    try {
      const schema = Joi.object({
        weight: Joi.number().min(30).max(300).required(),
        record_time: Joi.date().optional(),
        record_type: Joi.string().valid('morning', 'evening', 'anytime').default('anytime'),
        note: Joi.string().allow('').optional()
      });

      const { error, value } = schema.validate(req.body);
      if (error) {
        return res.status(400).json({
          success: false,
          error: error.details[0].message
        } as ApiResponse);
      }

      // 如果没有提供时间，使用当前时间
      if (!value.record_time) {
        value.record_time = new Date();
      }

      const id = await this.weightDao.addWeightRecord(value);
      
      res.status(201).json({
        success: true,
        data: { id, ...value },
        message: '体重记录添加成功'
      } as ApiResponse);
    } catch (error) {
      console.error('添加体重记录失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 获取体重记录
  getWeights = async (req: Request, res: Response) => {
    try {
      const { start_date, end_date } = req.query;
      
      const records = await this.weightDao.getWeightRecords(
        start_date as string, 
        end_date as string
      );
      
      res.json({
        success: true,
        data: records
      } as ApiResponse);
    } catch (error) {
      console.error('获取体重记录失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 获取K线数据
  getKLineData = async (req: Request, res: Response) => {
    try {
      const schema = Joi.object({
        period: Joi.string().valid('day', 'week', 'month', 'year').default('day'),
        limit: Joi.number().min(1).max(365).default(100)
      });

      const { error, value } = schema.validate(req.query);
      if (error) {
        return res.status(400).json({
          success: false,
          error: error.details[0].message
        } as ApiResponse);
      }

      const klineData = await this.weightDao.generateKLineData(value.period, value.limit);
      
      res.json({
        success: true,
        data: {
          period: value.period,
          kline: klineData
        }
      } as ApiResponse);
    } catch (error) {
      console.error('获取K线数据失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 获取最新体重
  getLatestWeight = async (req: Request, res: Response) => {
    try {
      const latest = await this.weightDao.getLatestWeight();
      
      res.json({
        success: true,
        data: latest
      } as ApiResponse);
    } catch (error) {
      console.error('获取最新体重失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 获取指标数据
  getIndicators = async (req: Request, res: Response) => {
    try {
      const days = parseInt(req.query.days as string) || 30;
      const indicators = await this.weightDao.getIndicatorData(days);
      
      res.json({
        success: true,
        data: indicators
      } as ApiResponse);
    } catch (error) {
      console.error('获取指标数据失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 获取分时图数据
  getTimeshareData = async (req: Request, res: Response) => {
    try {
      const date = req.query.date as string || moment().format('YYYY-MM-DD');
      const timeshareData = await this.weightDao.getTimeshareData(date);
      
      res.json({
        success: true,
        data: {
          date,
          records: timeshareData
        }
      } as ApiResponse);
    } catch (error) {
      console.error('获取分时图数据失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 删除体重记录
  deleteWeight = async (req: Request, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      if (isNaN(id)) {
        return res.status(400).json({
          success: false,
          error: '无效的记录ID'
        } as ApiResponse);
      }

      const success = await this.weightDao.deleteWeightRecord(id);
      
      if (success) {
        res.json({
          success: true,
          message: '记录删除成功'
        } as ApiResponse);
      } else {
        res.status(404).json({
          success: false,
          error: '记录不存在'
        } as ApiResponse);
      }
    } catch (error) {
      console.error('删除体重记录失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 更新体重记录
  updateWeight = async (req: Request, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      if (isNaN(id)) {
        return res.status(400).json({
          success: false,
          error: '无效的记录ID'
        } as ApiResponse);
      }

      const schema = Joi.object({
        weight: Joi.number().min(30).max(300).optional(),
        record_time: Joi.date().optional(),
        record_type: Joi.string().valid('morning', 'evening', 'anytime').optional(),
        note: Joi.string().allow('').optional()
      });

      const { error, value } = schema.validate(req.body);
      if (error) {
        return res.status(400).json({
          success: false,
          error: error.details[0].message
        } as ApiResponse);
      }

      const success = await this.weightDao.updateWeightRecord(id, value);
      
      if (success) {
        res.json({
          success: true,
          message: '记录更新成功'
        } as ApiResponse);
      } else {
        res.status(404).json({
          success: false,
          error: '记录不存在'
        } as ApiResponse);
      }
    } catch (error) {
      console.error('更新体重记录失败:', error);
      res.status(500).json({
        success: false,
        error: '服务器内部错误'
      } as ApiResponse);
    }
  };

  // 清除所有数据
  clearAllData = async (req: Request, res: Response) => {
    try {
      await this.weightDao.clearAllData();
      res.json({
        success: true,
        message: '所有数据已清除'
      } as ApiResponse);
    } catch (error) {
      console.error('清除数据失败:', error);
      res.status(500).json({
        success: false,
        error: '清除数据失败'
      } as ApiResponse);
    }
  };

  // 生成模拟数据
  generateMockData = async (req: Request, res: Response) => {
    try {
      const days = parseInt(req.query.days as string) || 30;
      const startWeight = parseFloat(req.query.start_weight as string) || 90.0;
      
      // 清空现有数据
      await this.weightDao.clearAllData();
      
      // 从4月10日开始生成数据
      const startDate = moment('2025-04-10');
      const endDate = moment('2025-08-30');
      const totalDays = endDate.diff(startDate, 'days') + 1;
      
      console.log(`生成数据：从 ${startDate.format('YYYY-MM-DD')} 到 ${endDate.format('YYYY-MM-DD')}，共 ${totalDays} 天`);
      
      let currentWeight = startWeight; // 起始体重89kg
      
      for (let day = 0; day < totalDays; day++) {
        const date = startDate.clone().add(day, 'days');
        const dateStr = date.format('YYYY-MM-DD');
        
        // 创建真实的增重趋势曲线 (89kg -> 95kg)
        let baseWeight: number;
        const progress = day / totalDays; // 0 到 1 的进度

        if (progress < 0.25) {
          // 第一阶段：4月10日-5月10日，体重从89kg缓慢上升到90.5kg
          baseWeight = 89 + progress * 6 + Math.sin(day * 0.3) * 0.4;
        } else if (progress < 0.5) {
          // 第二阶段：5月11日-6月10日，体重继续上升到92kg，略有波动
          baseWeight = 90.5 + (progress - 0.25) * 6 + Math.sin(day * 0.2) * 0.5;
        } else if (progress < 0.75) {
          // 第三阶段：6月11日-7月10日，体重加速上升到94kg，期间有小幅下降
          baseWeight = 92 + (progress - 0.5) * 8 - Math.sin(day * 0.4) * 0.6;
        } else {
          // 第四阶段：7月11日-8月30日，体重最终达到95kg，并保持波动
          baseWeight = 94 + (progress - 0.75) * 4 + Math.sin(day * 0.3) * 0.4;
        }

        // 确保体重在89-95kg范围内
        baseWeight = Math.max(89, Math.min(95, baseWeight));
        
        // 添加更自然的随机波动
        const randomFactor = (Math.random() - 0.5) * 0.6; // ±0.3kg随机波动
        baseWeight += randomFactor;

        // 每天生成6条记录，确保有上影线和下影线
        const dailyMin = baseWeight - 0.4; // 当天最低体重
        const dailyMax = baseWeight + 0.4; // 当天最高体重
        
        // 确保有足够的波动来显示影线
        const minVariation = 0.4; // 最小波动0.4kg
        if (dailyMax - dailyMin < minVariation) {
          // 增加波动
          const extraVariation = (minVariation - (dailyMax - dailyMin)) / 2;
          const newHigh = dailyMax + extraVariation;
          const newLow = dailyMin - extraVariation;
          
          // 更新记录中的最高和最低值
          // 由于records是动态生成的，这里无法直接更新records中的值
          // 需要重新生成records，或者在生成时考虑波动
        }
        
        // 插入记录到数据库
        for (let i = 0; i < 6; i++) { // 每天生成6条记录
          const recordTime = moment(date).add(6 + i * 3, 'hours').format('YYYY-MM-DD HH:mm:ss');
          const recordWeight = baseWeight + (Math.random() - 0.5) * 0.6; // 随机波动
          const recordType = i === 0 ? 'morning' : i === 5 ? 'evening' : 'anytime'; // 第一条和最后一条是开盘/收盘

          await this.weightDao.addWeightRecord({
            weight: parseFloat(recordWeight.toFixed(1)),
            record_time: new Date(recordTime),
            record_type: recordType as any,
            note: `模拟数据-${recordType === 'morning' ? '早上' : recordType === 'evening' ? '晚上' : '随时'}`
          });
        }
      }
      
      res.json({
        success: true,
        message: `成功生成${totalDays}天的模拟数据（4月10日-8月30日），每天6条记录，体重从89kg到95kg`,
        data: {
          days: totalDays,
          startWeight: startWeight,
          endWeight: 95
        }
      });
    } catch (error) {
      console.error('生成模拟数据失败:', error);
      res.status(500).json({
        success: false,
        error: '生成模拟数据失败'
      } as ApiResponse);
    }
  };
}
